home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turnbull China Bikeride
/
Turnbull China Bikeride - Disc 1.iso
/
ARGONET
/
PD
/
MATHS
/
RLAB
/
RLAB125.ZIP
/
!RLaB
/
help_ai
/
function
< prev
next >
Wrap
Text File
|
1995-02-18
|
15KB
|
489 lines
function:
This help file covers several aspects of functions:
1) Introduction
2) Variable scoping
3) Function arguments
4) Function return values
5) Function recursion
6) Special topics
1) Introduction ------------------------------------------------
Functions are an essential part of the language. Learning how
to create and use functions will greatly add to the benefits
of using RLaB.
It is important to remember that functions adhere to the RLaB
rule: "everything is a variable". Functions are variables, and
like the other types or classes of variables in RLaB can be
printed (although it will be hard to understand the output),
copied, and renamed. Functions cannot act as operands to
numeric operators, although the result of the function usually
can. Since function calls are evaluated "in-place" they can be
used within other expressions, for example:
> sin(cos(1.0))
0.514
> sin( [ cos(0.3), sqrt(cos(0.3)) ] )
0.817 0.829
The syntax used for function definition is a little unusual...
Example:
> sum = function (s)
{
local(i, Sum);
Sum = 0;
for(i in 1:size(s)) {
Sum = Sum + s[i];
}
return Sum;
};
>
creates a function, and assigns it to the variable `sum'.
Sum is invoked like:
> sum( [1,2,3,4,5] )
15
2) Variable Scopes ---------------------------------------------
When you start a RLaB session, either interactively or in
batch-mode, you create an environment. The environment or
workspace consists of the built-in functions, and any other
variables or functions you may have added. The workspace will
also be referred to as the global-symbol-table or the global
scope.
There are two other types of environment available: a
function's local environment and a file's static environment
(we will use the term environment and scope interchangeably).
A function's local scope is temporary, it is created when the
function is invoked, and is destroyed when the function
returns. A file's static scope is created when the file is
loaded, and remains intact until the RLaB session is
terminated.
The different scopes serve to protect data from operations
that occur in the other scopes. There is some degree of
overlap in order to allow flexibility. Functions can affect
file-static and global scopes; statements within files can
affect statements within other files and the global
scope. More simply put, the "lower" scopes generally have
access to the "higher" scopes. When a variable is used, RLaB
uses certain rules to "bind" the variable. When we use the
term bind or bound, we mean that the variable name is
associated with an entry in one of the three types of symbol
tables.
File-Scope: Variables that are in a file (but not within a
function) are bound to the global-symbol-table
(global-scope or global-environment) unless a
static declaration is used. When a variable is
declared static (see `help static') it is bound to
the file's symbol table. From that point on, the
variable will remain bound to the file's
scope. When a variable is declared static, it is
not visible from the global environment or from
any other files.
Function Local Scope: In general, variables used within a
function (other than the function's arguments) are
bound to the function's local scope (there are
ways to override this behavior). Variables bound
to a function's local scope are not visible from a
file's scope or from the global scope. They are
created (undefined) when the function is invoked,
and destroyed when the function returns.
There are exceptions: variables used in a function
context are bound to the global-symbol-table. For
example:
x = a * sin ( pi )
`sin' is used in a function context, and is bound
to the global scope, while `x', `a', and`pi' are
bound to the function's local environment.
Function's that are defined within a file have
full access to the file's static variables.
Function variables will be bound to the file's
scope before local binding occurs. For example:
---- beginning of file.r ----
static (A, pi)
A = 1.e-3;
pi = atan(1)*4;
fun = function ( a ) { return A*sin(pi*A*a); }
---- end of file.r ----
When `fun' is created it binds `A' and `pi'
to file.r's static environment.
There are two declarations: `global' and `local'
that can be used to override the default behavior
if necessary. Variables declared local will be
bound to to the function's local scope, and
variable declared global will be bound to the
global scope.
**NOTE: There is one more special exception (for
advanced usage): Function variables can be
members of a list, or members of a list, that is a
member of another list, etc, etc... In effect this
allows users to hide or protect variables and
functions in an arbitrary manner. Thus, when RLaB
sees something like:
ML.e1.signal( a )
it does not bind `ML' to the global scope. In this
context RLaB cannot bind the function until
runtime, so the list is by default bound to the
function's local scope. This behavior can be
changed by using the global, or static
declarations.
The built-in function fvscope performs a variable scope
analysis of any user-function. For example:
---- beginning of file.r ----
static (stat) // Keep track of some statistic.
stat.n = 0;
stat.total = 0;
x = function (a, b)
{
local (a)
global (pi)
for( i in 1:a.nr )
{
a[;i] = a[;i]*norm(a);
}
retv = 2*pi*norm(a)*b;
stat.n = stat.n + 1;
stat.total = stat.total + retv;
return << val = retv; avg = stat.total/stat.n >>;
};
---- end of file.r ----
> local ("./file.r");
> fvscope(x);
Function Variable SCOPE analysis for : x
Filename: ./jnk.r
line GLOBAL ARG LOCAL
10 Local-Var: i
10 Local-Var: a
12 Local-Var: a
12 Local-Var: i
12 Local-Var: a
12 Local-Var: i
12 Local-Var: a
12 Global-Var: norm
14 Local-Var: retv
14 Global-Var: pi*
14 Local-Var: a
14 Global-Var: norm
14 Arg-Var: b
15 Static-Var: stat
15 Static-Var: stat
16 Static-Var: stat
16 Static-Var: stat
16 Local-Var: retv
17 Local-Var: retv
17 Static-Var: stat
17 Static-Var: stat
The function `x' is used to compute some arbitrary value. The
list `stat' is used to keep track of how many times `x' is
called, and to compute the average of the return
value. fvscope shows us, line by line, each variable, and how
it is bound.
3) Function arguments ------------------------------------------
RLaB supports both "pass by reference" and "pass by value" for
passing arguments to a function.
Pass by reference means that the arguments, while still
referred to be there declared names, are in fact bound to the
caller's scope. Thus, the function can directly modify
variables in the caller's scope.
Pass by value means that a function cannot modify variables in
the caller's scope - essentially, an argument that is passed
by value is copied, and the copied value is passed to the
function to operate on.
Pass by reference can be considered the default behavior,
since it takes no special effort on the user's part. Pass by
value is achieved by declaring function arguments to be
local. For example:
// Pass by reference
> myf = function ( A ) { A = "changed"; return A; }
<user-function>
> B=10;
> myf(B);
> B
B =
changed
// Pass by value
> myf = function ( A ) { local (A) A = "changed"; return A; }
<user-function>
> B=10;
> myf(B);
> B
B =
10
In the previous example B, a variable in the global workspace,
is changed by myf (pass by reference). In the second part of
the example, the function argument A, is redeclared to be
local. This redeclaration forces the function argument to be
passed by value.
One advantage of this behavior is that users can create
functions and selectively decide which variables should be
passed by reference, and which should be passed by value.
* * *
You do not have to call a function with the same number of
arguments specified in the definition. If you invoke a
function with more arguments than declared, the result is an
error. If you call the function with less arguments than
declared, RLaB will pad the argument list with UNDEFINED,
objects. Additionally, commas may be used to "skip" arguments
that are unnecessary. for each argument that is "skipped" an
UNDEFINED variable is passed to the function during execution.
UNDEFINED arguments can be detected with the exist function,
for example:
if (!exist (ARG))
{
ARG = 0; // Initialize undefined argument
}
The function-local variable `nargs' is automatically
initialized to the argument number of the last specified
argument in the function call. For example:
testf = function ( a, b, c, d, e )
{
nargin
}
> testf ( 1 , 2 );
2
> testf ( 1 , , 2 );
3
> testf ( 1 , , 2, 3 );
4
* * *
Lists can be used to get the effect of variable argument
lists. If you are not familiar with lists, then now would be a
good time to `help LIST'. A function can take a list as an
argument and then pull the actual number of list elements, and
their values, from the list when the function is called. For
example:
> vlistf = function( l )
{
local(i,x);
printf( "number of elements in variable arg-list = %i\n", size(l) );
// Pull each element from the list
for( i in 1:size(l) )
{
x = l.[i];
// now do something with x
}
};
> vlistf( << "string"; [1,2;3,4] >> )
number of elements in variable arg-list = 2
* * *
Functions can take other functions as arguments, for example:
> trick = function ( a , b )
{
a(b)
};
> trick( eye, [3,3] );
matrix columns 1 thru 3
1 0 0
0 1 0
0 0 1
Note that the function name, passed as an argument, did not
need quotes. This is so because functions are variables in the
same sense as scalars, strings, and matrices. The variable a
in the previous function example refers to the function eye,
since function args are passed by reference.
4) Function return values --------------------------------------
All functions return a value, although the return statement is
optional. If a return statement is not used, then the function
will return 0 (zero) to the calling environment. If the return
statement is used, the result of the return statement is
passed back to the calling environment.
Functions can only return a single entity to the calling
environment. If it is necessary to return more than one
entity, a list can be used to group multiple entities together
for return.
Example:
We want to write a function that creates a set of matrices (a
state-space model). We will write such a function, and group
the separate matrices together in a list.
> ss = function( w )
{
local(A, B, n);
n = size( w )[1];
A = [ zeros(n,n), eye(n,n);
-w; zeros(n,n) ];
B = ones(n,n);
return << A = A; B = B >>;
};
>
The return statement creates the list, and assign the names
`A' and `B' to it's members.
Since functions are evaluated "in-place" their return values
can be manipulated in the usual ways, for example:
> eig(symm(rand(3,3))).val
val =
-0.937 0.571 1.81
> eig(symm(rand(3,3))).val[2]
0.191
> rand(10,10)[1,3,5;2,4,6]
0.29 0.411 0.345
0.561 0.686 0.0287
0.269 0.324 0.57
5) Function recursion ------------------------------------------
Functions can call themselves recursively. For a function to
call itself recursively, the special keyword `$self' must be
used. `$self' must be used because the statements within a
function are compiled before the function is assigned to a
variable. Therefore, the function cannot resolve a recursive
reference without `$self'.
Example:
> fact = function (f)
{
if(f <= 1) {
return 1;
else
return f*$self(f-1);
}
};
> fact(10)
3628800
The local statement in the previous function makes `a' local
to the function `x'. Since `a' is also a function argument, it
is copied into the local variable `a', which is used for the
throughout the function. As you can see `a' does not even show
up as an argument variable in the output from fvscope.
Since `i' is not explicitly declared, it defaults to a local
variable with initial value undefined. When the function
returns the variable `i' (and all other local variables) will
cease to exist. When x() is called again `i' (and all other
local variables) will again be re-initialized undefined. The
local statement must be the 1st statement in a function, and
only one local statement is allowed. If you must declare alot
of local variables, then break the local statement with a
continuation. Note that `norm', although undeclared, is a
global variable. This is because `norm' is a function. Since
functions cannot be entirely local to another function it
makes no sense to have to declare all functions global.
The global statement tells the function to get `pi' from the
global workspace. The global statement must follow the local
statement, and precede any executable function statements.
6) Special Topics ----------------------------------------------
A) Although pass by reference is the default behavior
for function arguments, there are some instances where
this may not seem true (but it is). For example, when
you pass part of a matrix into a function you cannot
modify the original matrix.
> x = function ( a ) { global (pi) a[1] = pi; }
<user-function>
> z=rand(2,2);
> z
z =
0.0369 0.665
0.162 0.0847
> x(z);
> z
z =
3.14 0.665
0.162 0.0847
> x(z[2]);
> z
z =
3.14 0.665
0.162 0.0847
> y
UNDEFINED
> x(y=z[2]);
> y
y =
3.14
You can see that in the first function call, z is
passed by reference. In the second call, the second
element of z (z[2]) is copied into a temporary
variable, which in turn is passed by reference to the
function. In the last call the temporary variable is
stored in the variable y, which as you can see, is
passed by reference to the function for modification.
----------------------------------------------------------------